package com.deng.framework.context.support;

import com.deng.framework.beans.BeansException;
import com.deng.framework.beans.factory.ConfigurableListableBeanFactory;
import com.deng.framework.beans.factory.config.BeanFactoryPostProcessor;
import com.deng.framework.beans.factory.config.BeanPostProcessor;
import com.deng.framework.context.ApplicationEvent;
import com.deng.framework.context.ApplicationListener;
import com.deng.framework.context.ConfigurableApplicationContext;
import com.deng.framework.context.event.ApplicationEventMulticaster;
import com.deng.framework.context.event.ContextClosedEvent;
import com.deng.framework.context.event.ContextRefreshedEvent;
import com.deng.framework.context.event.SimpleApplicationEventMulticaster;
import com.deng.framework.core.convert.ConversionService;
import com.deng.framework.core.io.DefaultResourceLoader;

import java.util.Collection;
import java.util.Map;

/**
 * context中的抽象类实现
 * 继承了ConfigurableApplicationContext表明这个类是用来实现context的抽象类
 * 由于ApplicationContext继承了ListBeanFactory，所以这里也有一些相关的方法实现
 */
public abstract class AbstractApplicationContext extends DefaultResourceLoader implements ConfigurableApplicationContext {

    public static final String APPLICATION_EVENT_MULTICASTER_BEAN_NAME = "applicationEventMulticaster";

    private ApplicationEventMulticaster applicationEventMulticaster;

    /**
     * 主要的实现函数，这里的算法流程已经写在下面了，这里使用了很浓厚的面向对象的思想
     * 注意，我们在获取了beanFactory后，后面所有的操作都是在对beanFactory进行增加或者修改参数。这里最主要的类是ConfigurableListableBeanFactory，一切的操作都是在对这个类进行操作
     * 由于java中传参对于class这种复杂的对象都是引用形式，所以我们可以说这里的方法都是在对beanFactory进行增加或者修改参数
     *
     * ps:refresh和createBean是IOC中最重要的两个函数，这两个函数搞明白了，IOC就通了
     */
    @Override
    public void refresh() throws BeansException {
        // 1. 创建 BeanFactory，并加载 BeanDefinition
        refreshBeanFactory();

        // 2. 获取 BeanFactory
        ConfigurableListableBeanFactory beanFactory = getBeanFactory();

        // 3. 添加 ApplicationContextAwareProcessor，让继承自 ApplicationContextAware 的 Bean 对象都能感知所属的 ApplicationContext
        beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));

        // 4. 在 Bean 实例化之前，执行 BeanFactoryPostProcessor (Invoke factory processors registered as beans in the context.)
        invokeBeanFactoryPostProcessors(beanFactory);

        // 5. BeanPostProcessor 需要提前于其他 Bean 对象实例化之前执行注册操作
        registerBeanPostProcessors(beanFactory);

        // 6. 初始化事件发布者
        initApplicationEventMulticaster();

        // 7. 注册事件监听器
        registerListeners();

        // 8. 设置类型转换器、提前实例化单例Bean对象
        finishBeanFactoryInitialization(beanFactory);

        // 9. 发布容器刷新完成事件
        finishRefresh();

    }

    //发布容器刷新完成事件(finishRefresh)，发布了第一个服务器启动完成后的事件，这个事件通过 publishEvent 发布出去，其实也就是调用了 applicationEventMulticaster.multicastEvent(event); 方法。
    private void finishRefresh() {
        publishEvent(new ContextRefreshedEvent(this));
    }

    //因为这个方法不同的实现类有不同的实现，所以先写一个抽象方法，具体类具体实现
    protected abstract void refreshBeanFactory() throws BeansException;

    protected abstract ConfigurableListableBeanFactory getBeanFactory();

    /**
     * BeanPostProcessor部分
     */
    private void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
        Map<String, BeanFactoryPostProcessor> beanFactoryPostProcessorMap = beanFactory.getBeansOfType(BeanFactoryPostProcessor.class);
        for (BeanFactoryPostProcessor beanFactoryPostProcessor : beanFactoryPostProcessorMap.values()) {
            //执行 BeanFactoryPostProcessor
            beanFactoryPostProcessor.postProcessBeanFactory(beanFactory);
        }
    }

    private void registerBeanPostProcessors(ConfigurableListableBeanFactory beanFactory) {
        Map<String, BeanPostProcessor> beanPostProcessorMap = beanFactory.getBeansOfType(BeanPostProcessor.class);
        for (BeanPostProcessor beanPostProcessor : beanPostProcessorMap.values()) {
            //在对应的bean工厂在加入BeanPostProcessor，从而在beanfactory的createBean函数中可以执行BeanPostProcessor中的方法
            beanFactory.addBeanPostProcessor(beanPostProcessor);
        }
    }

    /**
     * 类型转换器+提前实例化单例Bean对象部分
     */
    // 设置类型转换器、提前实例化单例Bean对象
    protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
        // 设置类型转换器
        if (beanFactory.containsBean("conversionService")) {
            Object conversionService = beanFactory.getBean("conversionService");
            if (conversionService instanceof ConversionService) {
                beanFactory.setConversionService((ConversionService) conversionService);
            }
        }

        // 提前实例化单例Bean对象
        beanFactory.preInstantiateSingletons();
    }

    /**
     * 自定义销毁部分
     */
    //注册钩子
    @Override
    public void registerShutdownHook() {
        //可以看出钩子执行的是close方法
        Runtime.getRuntime().addShutdownHook(new Thread(this::close));
    }

    //关闭方法
    @Override
    public void close() {
        // 发布容器关闭事件
        publishEvent(new ContextClosedEvent(this));

        getBeanFactory().destroySingletons();
    }

    /**
     * 事件部分
     */
    //这个是个比较重要的函数，我们需要BeanDefine链表中的listener先识别出来然后放入事件广播器的listener链表中，
    // 然后才能在事件广播的时候正确的获取消息,这里通过 getBeansOfType 方法获取到所有从 spring.xml 中加载到的事件配置 Bean 对象。
    private void registerListeners() {
        Collection<ApplicationListener> applicationListeners = getBeansOfType(ApplicationListener.class).values();
        for(ApplicationListener listener : applicationListeners){
            applicationEventMulticaster.addApplicationListener(listener);
        }
    }

    //主要用于实例化一个 SimpleApplicationEventMulticaster，这是一个事件广播器。
    private void initApplicationEventMulticaster() {
        ConfigurableListableBeanFactory beanFactory = getBeanFactory();
        //不知道传个beanFactory进去有啥用，后面也不知道为啥要将其注册到实例化的链表中
        applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
        beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME,applicationEventMulticaster);
    }

    //event-发布消息
    @Override
    public void publishEvent(ApplicationEvent event) {

        applicationEventMulticaster.multicastEvent(event);
    }

    /**
     * 对ListBeanFactory中一些相关的方法实现
     */
    @Override
    public <T> Map<String, T> getBeansOfType(Class<T> type) throws BeansException {
        return getBeanFactory().getBeansOfType(type);
    }

    @Override
    public String[] getBeanDefinitionNames() {
        return getBeanFactory().getBeanDefinitionNames();
    }

    @Override
    public Object getBean(String name) throws BeansException {
        return getBeanFactory().getBean(name);
    }

    @Override
    public Object getBean(String name, Object... args) throws BeansException {
        return getBeanFactory().getBean(name, args);
    }

    @Override
    public <T> T getBean(String name, Class<T> requiredType) throws BeansException {
        return getBeanFactory().getBean(name, requiredType);
    }

    @Override
    public <T> T getBean(Class<T> requiredType) throws BeansException {
        return getBeanFactory().getBean(requiredType);
    }

    @Override
    public boolean containsBean(String name) {
        return getBeanFactory().containsBean(name);
    }

}
